/*
 * TP1 Organizacion de Computadoras 66.20
 * Práctica: Santi - Perez Masci
 * Integrantes:
 * 				Pereira, Fernando Roque 91610
 *				Montoya, Diego Ramiro 91939
 *				Aguila Cudicio, Barbara 92071
 *
 */

#define ERROR_CARACTER_INVALIDO 1
#define ERROR_LECTURA_ESCRITURA_ARCHIVO 2
#define ERROR_DELIM_INVALIDO 3
#define ERROR_COMANDOS 4
#define ERROR_INPUT_FILE_NOT_CREATED 5
#define ERROR_OUTPUT_FILE_NOT_CREATED 6

#define MSG_HELP "Usage:\
					\n tp0 -h\
					\n tp0 -V\
					\n tp0 [options]\
				\n\n Options:\
					\n -h, --help		Print this information.\
					\n -V, --version	Print version and quit.\
					\n -O, --octal		Octal dump mode: encode the input (binary file) in octal format (default).\
					\n -b, --binary		Binary mode: decode the input (octal dump file) in binary format.\
					\n -i, --input		Path to input file (defaults to stdin).\
					\n -o, --output		Path to output file (defaults to stdout)).\
					\n -l, --length		Number of octal bytes per line (line length) at the output in octal dump mode (0 = default = no limit).\
					\n -d, --delimiter	Delimiter between octal bytes. Could be a string, not only a single byte. Used as delimiter for octal output and input files (default: none).\n\n"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <limits.h>
#include <math.h>
#include "odump.h"

int main (int argc, char* argv[]){

	int c = 0, retorno = 0;
	unsigned long max_bytes = ULONG_MAX;
	int octal = 1; //Flag para ver el modo de encoding

	//Estructura que se pasa por parámetro a función 'getopt_long'
	static struct option long_commands[] = {
	                   {"help",0,NULL,'h'},
	                   {"version",0,NULL,'V'},
	                   {"octal",0, NULL,'O'},
	                   {"binary",0,NULL,'b'},
	                   {"input",1,NULL,'i'},
	                   {"output",1,NULL,'o'},
	                   {"length",1,NULL,'l'},
	                   {"delimiter",1,NULL,'d'},
	                   {0,0,0,0}
	               };

	opterr = 0; //Se indica 0 para que no imprima directamente mensaje de error

	FILE* inputFile = stdin;
	FILE* outputFile = stdout;

	struct odump_opts odump_options;

	//Inicializo length y delim
	odump_options.length = 0;
	odump_options.delim = "";

	/*	getopt_long: 	Devuelve los parametros en el int c. Si no hay mas parametros,
	 * 					devuelve -1.
	 * 		char* optarg - Nos da el argumento a analizar.
	*/
	while (((c = getopt_long(argc,argv,"hVObi:o:l:d:",long_commands,NULL)) != -1)){
		switch (c){
			case 'h': 	printf(MSG_HELP);
						return 0;
						break;

			case 'V': 	printf("\nVersión 1.0 \n\n");
						return 0;
						break;

			case 'O': 	octal = 1;
						break;

			case 'b': 	octal = 0;
						break;

			case 'i': 	if (strcmp(optarg,"-") != 0){
							inputFile = fopen(optarg,"rb");
							if (inputFile == NULL){
								printf("inputFile == NULL\n");
								fprintf(stderr, "Archivo de entrada no generado \n\n");
								return (ERROR_INPUT_FILE_NOT_CREATED);
							}
						}
						break;

			case 'o': 	if (strcmp(optarg,"-") != 0){
							outputFile = fopen(optarg,"wb");
							if (outputFile == NULL){
								printf("outputFile == NULL\n");
								fprintf(stderr, "Archivo de salida no generado \n\n");
								return ERROR_OUTPUT_FILE_NOT_CREATED;
							}
						}
						break;

			case 'l': 	max_bytes = atoi(optarg); //Indica cantidad maxima de bytes a imprimir
						odump_options.length = max_bytes;
						break;

			case 'd': 	odump_options.delim = (const char*) malloc (sizeof(char)*strlen(optarg));
						strcpy((char*)odump_options.delim,optarg);
						break;

			case '?': 	fprintf(stderr,"Parámetro mal escrito o sin argumento necesario. "
										"Utilice -h para ver modo de uso y opciones\n\n");
						return ERROR_COMANDOS;
						break;

			default:	break;
		}
	}

	if (octal) retorno = odump_encode(fileno(inputFile), fileno(outputFile), &odump_options);
	else retorno = odump_decode(fileno(inputFile), fileno(outputFile), &odump_options);

	fclose(inputFile);
	fclose(outputFile);

	//Retorno de mensajes
	if (retorno != 0) fprintf(stderr,"%s",odump_errmsg[retorno - 1]);

	return retorno;
}
